package com.luom.fsp.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.luom.fsp.common.ErrorCode;
import com.luom.fsp.constant.CommonConstant;
import com.luom.fsp.constant.RedisConstant;
import com.luom.fsp.exception.BusinessException;
import com.luom.fsp.exception.ThrowUtils;
import com.luom.fsp.mapper.AfterSalesServiceMapper;
import com.luom.fsp.model.dto.afterSalesService.AfterSalesServiceQueryRequest;
import com.luom.fsp.model.entity.AfterSalesService;
import com.luom.fsp.model.entity.Order;
import com.luom.fsp.model.entity.User;
import com.luom.fsp.model.enums.OrderPayStatusEnum;
import com.luom.fsp.model.enums.OrderStatusEnum;
import com.luom.fsp.model.enums.ServiceStatusEnum;
import com.luom.fsp.model.enums.ServiceTypeEnum;
import com.luom.fsp.model.vo.AfterSalesServiceVO;
import com.luom.fsp.model.vo.OrderVO;
import com.luom.fsp.service.AfterSalesServiceService;
import com.luom.fsp.service.OrderService;
import com.luom.fsp.service.UserService;
import com.luom.fsp.utils.SqlUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.luom.fsp.constant.RedisConstant.DASHBOARD_KEY;

/**
 * 售后服务服务实现
 */
@Service
@Slf4j
public class AfterSalesServiceServiceImpl extends ServiceImpl<AfterSalesServiceMapper, AfterSalesService> implements AfterSalesServiceService {

    @Resource
    private UserService userService;

    @Resource
    private OrderService orderService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 校验数据
     *
     * @param afterSalesService
     * @param add               对创建的数据进行校验
     */
    @Override
    public void validAfterSalesService(AfterSalesService afterSalesService, boolean add) {
        ThrowUtils.throwIf(afterSalesService == null, ErrorCode.PARAMS_ERROR);

        Long id = afterSalesService.getId();
        Long orderId = afterSalesService.getOrderId();
        String serviceType = afterSalesService.getServiceType();
        String serviceStatus = afterSalesService.getServiceStatus();
        String serviceReason = afterSalesService.getServiceReason();
        String serviceImages = afterSalesService.getServiceImages();
        Date createTime = afterSalesService.getCreateTime();
        Date updateTime = afterSalesService.getUpdateTime();
        Integer isDelete = afterSalesService.getIsDelete();

        // 创建数据时，参数不能为空
        if (add) {
            ThrowUtils.throwIf(ObjectUtils.isEmpty(orderId), ErrorCode.PARAMS_ERROR, "订单不能为空");
            ThrowUtils.throwIf(ObjectUtils.isEmpty(serviceType), ErrorCode.PARAMS_ERROR, "售后服务类型不能为空");
            ThrowUtils.throwIf(ObjectUtils.isEmpty(serviceReason), ErrorCode.PARAMS_ERROR, "售后服务原因不能为空");
        }
        // 修改数据时，有参数则校验
        if (StringUtils.isNotBlank(serviceType)) {
            ThrowUtils.throwIf(!ServiceTypeEnum.getValues().contains(serviceType), ErrorCode.PARAMS_ERROR, "售后服务类型错误");
        }
        if (StringUtils.isNotBlank(serviceStatus)) {
            ThrowUtils.throwIf(!ServiceStatusEnum.getValues().contains(serviceStatus), ErrorCode.PARAMS_ERROR, "售后服务状态错误");
        }
    }

    /**
     * 获取查询条件
     *
     * @param afterSalesServiceQueryRequest
     * @return
     */
    @Override
    public QueryWrapper<AfterSalesService> getQueryWrapper(AfterSalesServiceQueryRequest afterSalesServiceQueryRequest) {
        QueryWrapper<AfterSalesService> queryWrapper = new QueryWrapper<>();
        if (afterSalesServiceQueryRequest == null) {
            return queryWrapper;
        }

        Long id = afterSalesServiceQueryRequest.getId();
        Long orderId = afterSalesServiceQueryRequest.getOrderId();
        Long userId = afterSalesServiceQueryRequest.getUserId();
        String serviceType = afterSalesServiceQueryRequest.getServiceType();
        String serviceStatus = afterSalesServiceQueryRequest.getServiceStatus();
        String serviceReason = afterSalesServiceQueryRequest.getServiceReason();
        String sortField = afterSalesServiceQueryRequest.getSortField();
        String sortOrder = afterSalesServiceQueryRequest.getSortOrder();

        // 精确查询
        queryWrapper.eq(ObjectUtils.isNotEmpty(orderId), "orderId", orderId);
        queryWrapper.eq(StringUtils.isNotBlank(serviceType), "serviceType", serviceType);
        queryWrapper.eq(StringUtils.isNotBlank(serviceStatus), "serviceStatus", serviceStatus);
        queryWrapper.eq(StringUtils.isNotBlank(serviceReason), "serviceReason", serviceReason);
        queryWrapper.eq(ObjectUtils.isNotEmpty(id), "id", id);
        queryWrapper.eq(ObjectUtils.isNotEmpty(userId), "userId", userId);

        // 排序规则
        queryWrapper.orderBy(SqlUtils.validSortField(sortField),
                sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);
        return queryWrapper;
    }

    /**
     * 获取售后服务封装
     *
     * @param afterSalesService
     * @param request
     * @return
     */
    @Override
    public AfterSalesServiceVO getAfterSalesServiceVO(AfterSalesService afterSalesService, HttpServletRequest request) {
        // 对象转封装类
        AfterSalesServiceVO afterSalesServiceVO = AfterSalesServiceVO.objToVo(afterSalesService);

        // 填充订单信息
        if (afterSalesService.getOrderId() != null) {
            Order order = orderService.getById(afterSalesService.getOrderId());
            afterSalesServiceVO.setOrder(orderService.getOrderVO(order, request));
        }

        // 填充用户名
        if (afterSalesService.getUserId() != null) {
            User user = userService.getById(afterSalesService.getUserId());
            afterSalesServiceVO.setUserName(user.getUserName());
        }

        return afterSalesServiceVO;
    }

    /**
     * 分页获取售后服务封装
     *
     * @param afterSalesServicePage
     * @param request
     * @return
     */
    @Override
    public Page<AfterSalesServiceVO> getAfterSalesServiceVOPage(Page<AfterSalesService> afterSalesServicePage, HttpServletRequest request) {
        List<AfterSalesService> afterSalesServiceList = afterSalesServicePage.getRecords();
        Page<AfterSalesServiceVO> afterSalesServiceVOPage = new Page<>(afterSalesServicePage.getCurrent(), afterSalesServicePage.getSize(), afterSalesServicePage.getTotal());
        if (CollUtil.isEmpty(afterSalesServiceList)) {
            return afterSalesServiceVOPage;
        }
        // 对象列表 => 封装对象列表
        List<AfterSalesServiceVO> afterSalesServiceVOList = afterSalesServiceList.stream().map(AfterSalesServiceVO::objToVo).collect(Collectors.toList());

        // 批量填充订单信息
        List<Long> orderIdList = afterSalesServiceList.stream().map(AfterSalesService::getOrderId).collect(Collectors.toList());
        List<Order> orderList = orderService.listByIds(orderIdList);
        Map<Long, Order> orderMap = orderList.stream().collect(Collectors.toMap(Order::getId, order -> order));
        for (AfterSalesServiceVO afterSalesServiceVO : afterSalesServiceVOList) {
            Long orderId = afterSalesServiceVO.getOrderId();
            if (orderId != null) {
                afterSalesServiceVO.setOrder(OrderVO.objToVo(orderMap.get(orderId)));
            }
        }

        // 批量填充用户名
        List<Long> userIdList = afterSalesServiceList.stream().map(AfterSalesService::getUserId).collect(Collectors.toList());
        List<User> userList = userService.listByIds(userIdList);
        Map<Long, User> userMap = userList.stream().collect(Collectors.toMap(User::getId, user -> user));
        for (AfterSalesServiceVO afterSalesServiceVO : afterSalesServiceVOList) {
            Long userId = afterSalesServiceVO.getUserId();
            if (userId != null) {
                afterSalesServiceVO.setUserName(userMap.get(userId).getUserName());
            }
        }


        afterSalesServiceVOPage.setRecords(afterSalesServiceVOList);
        return afterSalesServiceVOPage;
    }

    @Override
    public void deleteAfterSalesService(Long id, HttpServletRequest request) {
        User user = userService.getLoginUser(request);
        // 判断是否存在
        AfterSalesService oldAfterSalesService = this.getById(id);
        ThrowUtils.throwIf(oldAfterSalesService == null, ErrorCode.NOT_FOUND_ERROR);
        Long orderId = oldAfterSalesService.getOrderId();
        Order order = orderService.getById(orderId);
        // 仅本人或管理员可删除
        if (!order.getUserId().equals(user.getId()) && !userService.isAdmin(request)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        // 操作数据库
        boolean result = this.removeById(id);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
    }

    @Override
    @Transactional
    public long addAfterSalesService(AfterSalesService afterSalesService, HttpServletRequest request) {
        // 数据校验
        this.validAfterSalesService(afterSalesService, true);
        if (afterSalesService.getUserId() != null) {
            User byId = userService.getById(afterSalesService.getUserId());
            if (byId == null) {
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
            }
        } else {
            User loginUser = userService.getLoginUser(request);
            afterSalesService.setUserId(loginUser.getId());
        }
        // 订单已支付，但未发货，直接退款
        Order order = orderService.getById(afterSalesService.getOrderId());
        if (OrderStatusEnum.PAID.getValue().equals(order.getOrderStatus())) {
            order.setPaymentStatus(OrderPayStatusEnum.REFUNDED.getValue());
            order.setOrderStatus(OrderStatusEnum.REFUNDED.getValue());
            boolean result = orderService.updateById(order);
            if (result) {
                afterSalesService.setServiceStatus(ServiceStatusEnum.COMPLETED.getValue());
                updateRedis(order);
            }
        } else {
            afterSalesService.setServiceStatus(ServiceStatusEnum.PENDING.getValue());
            updateRedis();
        }
        // 写入数据库
        boolean result = this.save(afterSalesService);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return afterSalesService.getId();
    }

    @Override
    public void cancelAfterSalesService(Long id, HttpServletRequest request) {
        User user = userService.getLoginUser(request);
        // 判断是否存在
        AfterSalesService oldAfterSalesService = this.getById(id);
        ThrowUtils.throwIf(oldAfterSalesService == null, ErrorCode.NOT_FOUND_ERROR);
        Long orderId = oldAfterSalesService.getOrderId();
        Order order = orderService.getById(orderId);
        // 仅本人或管理员可删除
        if (!order.getUserId().equals(user.getId())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        oldAfterSalesService.setServiceStatus(ServiceStatusEnum.CANCEL.getValue());
        // 操作数据库
        boolean result = this.updateById(oldAfterSalesService);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
    }

    // 异步操作redis
    @Async("taskExecutor")
    public void updateRedis(Order order) {
        // 1. 转换 Date 到 LocalDate
        ZoneId zone = ZoneId.of("Asia/Shanghai");
        LocalDate orderDate = order.getCreateTime().toInstant()
                .atZone(zone)
                .toLocalDate();

        // 2. 判断是否是今天
        LocalDate today = LocalDate.now(zone);
        if (orderDate.isEqual(today)) {
            BigDecimal totalPrice = order.getTotalPrice();
            stringRedisTemplate.opsForHash().increment(
                    RedisConstant.DASHBOARD_KEY,
                    "todaySales",
                    totalPrice.negate().doubleValue()
            );
        }
        stringRedisTemplate.opsForHash().increment(DASHBOARD_KEY, "pendingShipment", -1);
//        String currentVal = (String) stringRedisTemplate.opsForHash().get(RedisConstant.DASHBOARD_KEY, "todaySales");
//        BigDecimal newVal = new BigDecimal(currentVal != null ? currentVal : "0").subtract(order.getTotalPrice());
//        stringRedisTemplate.opsForHash().put(RedisConstant.DASHBOARD_KEY, "todaySales", newVal.toPlainString());

    }

    @Async("taskExecutor")
    public void updateRedis() {
        stringRedisTemplate.opsForHash().increment(DASHBOARD_KEY, "afterSales", 1L);
    }


}
